﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using ModelChecking.ModelValidation.Utils;

namespace ModelChecking.ModelValidation.Analyser
{
	public class PoleAnalyzer
	{
		public PoleAnalyzer(bool isExtendLength, double extendLength, int WallWidthMultiple, bool useMaximumLengthLimit)
		{
			this.m_ExtendLengthInfo = new PoleAnalyzer.ExtendLengthInfo(isExtendLength, extendLength, (double)WallWidthMultiple, useMaximumLengthLimit);
		}

		public bool Analyse(List<Pole2D> poleList, ref List<Pole2D> analyzedPoleList)
		{
			bool result;
			try
			{
				if (poleList.Count == 0)
				{
					result = false;
				}
				else
				{
					List<Pole2D> poleList2 = this.SegmentPoleList(poleList);
					List<Pole2D> poleList3 = this.FilterOverlapPoleList(poleList2);
					List<Node2D> nodeInfos = new List<Node2D>();
					this.InitData(poleList3, Node2D.SearchType._Clockwise, ref nodeInfos);
					List<Pole2D> poleList4 = new List<Pole2D>();
					this.ExtendSingleEnd(nodeInfos, ref poleList4);
					List<Pole2D> poleList5 = this.SegmentPoleList(poleList4);
					List<Pole2D> poleList6 = this.FilterOverlapPoleList(poleList5);
					List<Node2D> theNodes = new List<Node2D>();
					this.InitData(poleList6, Node2D.SearchType._Clockwise, ref theNodes);
					this.RecursiveDeleteSingleNode(ref theNodes);
					this.MergeEdge(ref theNodes);
					this.GetAllPoleList(theNodes, ref analyzedPoleList);
					result = true;
				}
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private List<Pole2D> SegmentPoleList(List<Pole2D> poleList)
		{
			List<Pole2D> list = new List<Pole2D>();
			List<List<XYZ>> list2 = new List<List<XYZ>>();
			List<Curve> list3 = new List<Curve>();
			int i = 0;
			while (i < poleList.Count)
			{
				Pole2D pole2D = poleList[i];
				XYZ startPoint = pole2D.StartPoint;
				XYZ endPoint = pole2D.EndPoint;
				Curve item = null;
				try
				{
					if (pole2D.IsArcPole)
					{
						XYZ xyz = XYZ.BasisZ;
						if (Geometry.LessThan(pole2D.Bulge, 0.0))
						{
							xyz = -xyz;
						}
						XYZ center = pole2D.Center;
						XYZ xyz2 = Geometry.CalculatMidPoint(startPoint, endPoint, center, xyz);
						item = Arc.Create(startPoint, endPoint, xyz2);
					}
					else
					{
						item = Line.CreateBound(startPoint, endPoint);
					}
				}
				catch (Exception)
				{
					poleList.RemoveAt(i);
					i--;
					goto IL_DC;
				}
				goto IL_A9;
				IL_DC:
				i++;
				continue;
				IL_A9:
				list2.Add(new List<XYZ>
				{
					pole2D.StartPoint,
					pole2D.EndPoint
				});
				list3.Add(item);
				goto IL_DC;
			}
			for (i = 0; i < list3.Count; i++)
			{
				Curve curve = list3[i];
				for (int j = i + 1; j < list3.Count; j++)
				{
					Curve curve2 = list3[j];
					try
					{
						IntersectionResultArray intersectionResultArray;
						SetComparisonResult setComparisonResult = curve.Intersect(curve2, out intersectionResultArray);
						if (setComparisonResult == SetComparisonResult.Overlap)
						{
							foreach (object obj in intersectionResultArray)
							{
								IntersectionResult intersectionResult = (IntersectionResult)obj;
								if (intersectionResult.XYZPoint != null)
								{
									list2[i].Add(intersectionResult.XYZPoint);
									list2[j].Add(intersectionResult.XYZPoint);
								}
							}
						}
					}
					catch (Exception)
					{
					}
				}
			}
			for (i = 0; i < poleList.Count; i++)
			{
				Pole2D pole2D2 = poleList[i];
				Curve curve3 = list3[i];
				List<XYZ> intersectPoints = list2[i];
				List<XYZ> list4 = Common.UniqueAndSortIntersectPoints(curve3, intersectPoints);
				if (list4.Count >= 2)
				{
					if (list4.Count == 2)
					{
						list.Add(pole2D2);
					}
					else
					{
						double positiveHalfWidth = pole2D2.PositiveHalfWidth;
						double negativeHalfWidth = pole2D2.NegativeHalfWidth;
						XYZ center2 = pole2D2.Center;
						for (int k = 0; k < list4.Count - 1; k++)
						{
							XYZ xyz3 = list4[k];
							XYZ xyz4 = list4[k + 1];
							if (!Geometry.LessThan(xyz3.DistanceTo(xyz4), 0.0001))
							{
								try
								{
									if (pole2D2.IsArcPole)
									{
										Pole2D item2 = Pole2D.NewStructure2DPole(pole2D2.ComponentId, xyz3, xyz4, center2, XYZ.BasisZ, positiveHalfWidth, negativeHalfWidth);
										list.Add(item2);
									}
									else
									{
										Pole2D item3 = Pole2D.NewStructure2DPole(pole2D2.ComponentId, xyz3, xyz4, positiveHalfWidth, negativeHalfWidth);
										list.Add(item3);
									}
								}
								catch (Exception)
								{
								}
							}
						}
					}
				}
			}
			return list;
		}

		private void ExtendSingleEnd(List<Node2D> nodeInfos, ref List<Pole2D> newPoleList)
		{
			this.GetAllPoleList(nodeInfos, ref newPoleList);
			List<Pole2D> list = new List<Pole2D>();
			for (int i = 0; i < nodeInfos.Count; i++)
			{
				if (nodeInfos[i].PoleList.Count < 2)
				{
					XYZ position = nodeInfos[i].Position;
					Pole2D pole2D = nodeInfos[i].PoleList[0];
					double num = this.m_ExtendLengthInfo.ExtendLength(pole2D.PositiveHalfWidth + pole2D.NegativeHalfWidth);
					Pole2D pole2D2;
					if (pole2D.IsArcPole)
					{
						double angle = num / pole2D.Radius;
						XYZ xyz = position;
						XYZ xyz2 = XYZ.BasisZ;
						if (Geometry.IsEqual(pole2D.Normal, XYZ.BasisZ))
						{
							if (pole2D.TestPointPositionType(position) == Pole2D._tagPositionType._StartNode)
							{
								xyz2 = -XYZ.BasisZ;
							}
						}
						else
						{
							Pole2D._tagPositionType tagPositionType = pole2D.TestPointPositionType(position);
							if (tagPositionType == Pole2D._tagPositionType._EndNode)
							{
								xyz2 = -XYZ.BasisZ;
							}
						}
						XYZ pt = (xyz - pole2D.Center).Normalize();
						XYZ xyz3 = Geometry.RotateTo(pt, angle, xyz2);
						XYZ ptEnd = xyz3 * pole2D.Radius + pole2D.Center;
						pole2D2 = Pole2D.NewStructure2DPole(pole2D.ComponentId, xyz, ptEnd, pole2D.Center, xyz2, pole2D.PositiveHalfWidth, pole2D.NegativeHalfWidth);
						pole2D2.IsExtend = true;
					}
					else
					{
						XYZ xyz4 = pole2D.CurEndPoint(position);
						XYZ ptEnd2 = position + (position - xyz4).Normalize() * num;
						pole2D2 = Pole2D.NewStructure2DPole(pole2D.ComponentId, position, ptEnd2, pole2D.PositiveHalfWidth, pole2D.NegativeHalfWidth);
						pole2D2.IsExtend = true;
					}
					list.Add(pole2D2);
				}
			}
			this.OpreatingParallelExtendPoles(nodeInfos, ref list);
			newPoleList.AddRange(list);
		}

		private void OpreatingParallelExtendPoles(List<Node2D> nodeInfos, ref List<Pole2D> extendPoleList)
		{
			List<Pole2D> list = new List<Pole2D>();
			for (int i = 0; i < extendPoleList.Count; i++)
			{
				for (int j = i + 1; j < extendPoleList.Count; j++)
				{
					Pole2D pole2D = extendPoleList[i];
					Pole2D pole2D2 = extendPoleList[j];
					double val = pole2D.PositiveHalfWidth + pole2D2.PositiveHalfWidth;
					if (pole2D.IsArcPole == pole2D2.IsArcPole)
					{
						if (pole2D.IsArcPole)
						{
							if (Geometry.IsEqual(pole2D.Center, pole2D2.Center, 0.0001))
							{
								double val2 = Math.Abs(pole2D.Radius - pole2D2.Radius);
								if (!Geometry.Greaterthan_Or_Equal(val2, val))
								{
									XYZ xyz = pole2D.StartPoint;
									XYZ xyz2 = pole2D.EndPoint;
									if (!Geometry.IsEqual(pole2D.Normal, XYZ.BasisZ))
									{
										xyz = pole2D.EndPoint;
										xyz2 = pole2D.StartPoint;
									}
									XYZ ptS = pole2D2.StartPoint;
									XYZ ptE = pole2D2.EndPoint;
									if (!Geometry.IsEqual(pole2D2.Normal, XYZ.BasisZ))
									{
										ptS = pole2D2.EndPoint;
										ptE = pole2D2.StartPoint;
									}
									XYZ ptS2 = pole2D.Center + (xyz - pole2D.Center).Normalize() * pole2D2.Radius;
									XYZ ptE2 = pole2D.Center + (xyz2 - pole2D.Center).Normalize() * pole2D2.Radius;
									XYZ xyz3 = null;
									XYZ xyz4 = null;
									Geometry.OverlapType overlapType = Geometry.IsOverlapOfTwoArc(ptS2, ptE2, pole2D.Center, ptS, ptE, pole2D.Center, ref xyz3, ref xyz4);
									if (overlapType != Geometry.OverlapType._OT_None && overlapType != Geometry.OverlapType._OT_Linked)
									{
										XYZ xyz5 = Geometry.CalculatMidPoint(xyz3, xyz4, pole2D.Center, XYZ.BasisZ);
										this.ChangePoleEnd(xyz5, xyz3, xyz4, nodeInfos, ref pole2D2);
										extendPoleList[j] = pole2D2;
										XYZ xyz6 = pole2D.Center + (xyz3 - pole2D.Center).Normalize() * pole2D.Radius;
										XYZ xyz7 = pole2D.Center + (xyz4 - pole2D.Center).Normalize() * pole2D.Radius;
										XYZ xyz8 = Geometry.CalculatMidPoint(xyz6, xyz7, pole2D.Center, XYZ.BasisZ);
										this.ChangePoleEnd(xyz8, xyz6, xyz7, nodeInfos, ref pole2D);
										extendPoleList[i] = pole2D;
										if (!Geometry.IsEqual(xyz5, xyz8))
										{
											list.Add(Pole2D.NewStructure2DPole(ElementId.InvalidElementId, xyz5, xyz8, 0.0, 0.0));
										}
									}
								}
							}
						}
						else if (Geometry.IsParallel(pole2D.EndPoint - pole2D.StartPoint, pole2D2.EndPoint - pole2D2.StartPoint))
						{
							XYZ xyz9 = Geometry.CalculateFootPoint(pole2D2.StartPoint, pole2D2.EndPoint, pole2D.StartPoint);
							XYZ ptE3 = Geometry.CalculateFootPoint(pole2D2.StartPoint, pole2D2.EndPoint, pole2D.EndPoint);
							double val3 = xyz9.DistanceTo(pole2D.StartPoint);
							if (!Geometry.Greaterthan_Or_Equal(val3, val))
							{
								XYZ xyz10 = null;
								XYZ xyz11 = null;
								Geometry.OverlapType overlapType2 = Geometry.IsOverlapOfTwoLine(xyz9, ptE3, pole2D2.StartPoint, pole2D2.EndPoint, ref xyz10, ref xyz11, true, 1E-09);
								if (overlapType2 != Geometry.OverlapType._OT_None && overlapType2 != Geometry.OverlapType._OT_Linked)
								{
									XYZ xyz12 = Geometry.CalculatMidPoint(xyz10, xyz11);
									this.ChangePoleEnd(xyz12, xyz10, xyz11, nodeInfos, ref pole2D2);
									extendPoleList[j] = pole2D2;
									XYZ xyz13 = Geometry.CalculateFootPoint(pole2D.StartPoint, pole2D.EndPoint, xyz10);
									XYZ xyz14 = Geometry.CalculateFootPoint(pole2D.StartPoint, pole2D.EndPoint, xyz11);
									XYZ xyz15 = Geometry.CalculatMidPoint(xyz13, xyz14);
									this.ChangePoleEnd(xyz15, xyz13, xyz14, nodeInfos, ref pole2D);
									extendPoleList[i] = pole2D;
									if (!Geometry.IsEqual(xyz12, xyz15))
									{
										list.Add(Pole2D.NewStructure2DPole(ElementId.InvalidElementId, xyz12, xyz15, 0.0, 0.0));
									}
								}
							}
						}
					}
				}
			}
			extendPoleList.AddRange(list);
		}

		private void ChangePoleEnd(XYZ ptNew, XYZ ptRef1, XYZ ptRef2, List<Node2D> nodeInfos, ref Pole2D pole)
		{
			bool isExtend = pole.IsExtend;
			XYZ startPoint = pole.StartPoint;
			XYZ endPoint = pole.EndPoint;
			if (!Geometry.IsEqual(startPoint, ptRef1) && !Geometry.IsEqual(startPoint, ptRef2))
			{
				if (Geometry.IsEqual(endPoint, ptRef1) || Geometry.IsEqual(endPoint, ptRef2))
				{
					if (pole.IsArcPole)
					{
						if (this.FindNodeByPos(nodeInfos, endPoint) == null)
						{
							pole = Pole2D.NewStructure2DPole(pole.ComponentId, startPoint, ptNew, pole.Center, pole.Normal, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
						}
						else
						{
							pole = Pole2D.NewStructure2DPole(pole.ComponentId, ptNew, endPoint, pole.Center, pole.Normal, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
						}
						pole.IsExtend = isExtend;
						return;
					}
					if (this.FindNodeByPos(nodeInfos, endPoint) == null)
					{
						pole = Pole2D.NewStructure2DPole(pole.ComponentId, startPoint, ptNew, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
					}
					else
					{
						pole = Pole2D.NewStructure2DPole(pole.ComponentId, ptNew, endPoint, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
					}
					pole.IsExtend = isExtend;
				}
				return;
			}
			if (pole.IsArcPole)
			{
				if (this.FindNodeByPos(nodeInfos, startPoint) == null)
				{
					pole = Pole2D.NewStructure2DPole(pole.ComponentId, ptNew, endPoint, pole.Center, pole.Normal, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
				}
				else
				{
					pole = Pole2D.NewStructure2DPole(pole.ComponentId, startPoint, ptNew, pole.Center, pole.Normal, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
				}
				pole.IsExtend = isExtend;
				return;
			}
			if (this.FindNodeByPos(nodeInfos, startPoint) == null)
			{
				pole = Pole2D.NewStructure2DPole(pole.ComponentId, ptNew, endPoint, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
			}
			else
			{
				pole = Pole2D.NewStructure2DPole(pole.ComponentId, startPoint, ptNew, pole.PositiveHalfWidth, pole.NegativeHalfWidth);
			}
			pole.IsExtend = isExtend;
		}

		private void MergeEdge(ref List<Node2D> theNodes)
		{
			for (int i = 0; i < theNodes.Count; i++)
			{
				Node2D node2D = theNodes[i];
				if (node2D.PoleList.Count >= 2)
				{
					this.MergeEdgeInNode(ref node2D, ref theNodes);
					if (theNodes[i].PoleList.Count == 0)
					{
						theNodes.RemoveAt(i);
						i--;
					}
				}
			}
		}

		private void MergeEdgeInNode(ref Node2D curNode, ref List<Node2D> theNodes)
		{
			Pole2D newPole = null;
			for (int i = 0; i < curNode.PoleList.Count; i++)
			{
				for (int j = i + 1; j < curNode.PoleList.Count; j++)
				{
					try
					{
						if (Pole2D.MergeTwoPole(curNode.PoleList[i], curNode.PoleList[j], ref newPole))
						{
							this.UpdateLinkedPole(curNode, curNode.PoleList[i], theNodes, newPole);
							this.UpdateLinkedPole(curNode, curNode.PoleList[j], theNodes, newPole);
							curNode.RemoveEdge(j, false);
							curNode.RemoveEdge(i, false);
							i--;
							break;
						}
					}
					catch (Exception)
					{
						throw new Exception();
					}
				}
			}
		}

		private void UpdateLinkedPole(Node2D curNode, Pole2D curPole, List<Node2D> theNodes, Pole2D newPole)
		{
			XYZ pos = curPole.CurEndPoint(curNode.Position);
			Node2D node2D = this.FindNodeByPos(theNodes, pos);
			int num = node2D.FindLinkPoleWithOtherNode(curNode.Position, Node2D.SearchType._Anticlockwise);
			if (-1 != num)
			{
				node2D.PoleList[num] = newPole;
			}
		}

		private List<Pole2D> FilterOverlapPoleList(List<Pole2D> poleList)
		{
			List<Pole2D> list = new List<Pole2D>();
			list.AddRange(poleList);
			for (int i = 0; i < list.Count; i++)
			{
				for (int j = i + 1; j < list.Count; j++)
				{
					if (list[i].SameAs(list[j]))
					{
						list.RemoveAt(j);
						j--;
					}
				}
			}
			return list;
		}

		private void InitData(List<Pole2D> poleList, Node2D.SearchType searchType, ref List<Node2D> theNodes)
		{
			Dictionary<XYZ, Node2D> dictionary = new Dictionary<XYZ, Node2D>(new XYZComparer());
			foreach (Pole2D pole2D in poleList)
			{
				XYZ xyz = pole2D.StartPoint;
				if (!dictionary.ContainsKey(xyz))
				{
					Node2D value = new Node2D(xyz, new List<Pole2D>
					{
						pole2D
					});
					dictionary.Add(xyz, value);
				}
				else
				{
					Node2D node2D = dictionary[xyz];
					node2D.AddPole(pole2D, false);
				}
				xyz = pole2D.EndPoint;
				if (!dictionary.ContainsKey(xyz))
				{
					Node2D value2 = new Node2D(xyz, new List<Pole2D>
					{
						pole2D
					});
					dictionary.Add(xyz, value2);
				}
				else
				{
					Node2D node2D2 = dictionary[xyz];
					node2D2.AddPole(pole2D, false);
				}
			}
			foreach (KeyValuePair<XYZ, Node2D> keyValuePair in dictionary)
			{
				if (searchType == Node2D.SearchType._Anticlockwise)
				{
					keyValuePair.Value.AnticlockwiseSortElements();
				}
				else
				{
					keyValuePair.Value.ClockwiseSortElements();
				}
				theNodes.Add(keyValuePair.Value);
			}
		}

		private Node2D FindNodeByPos(List<Node2D> theNodes, XYZ pos)
		{
			foreach (Node2D node2D in theNodes)
			{
				if (Geometry.IsEqual(pos.DistanceTo(node2D.Position), 0.0, 0.0001))
				{
					return node2D;
				}
			}
			return null;
		}

		private void DeleteSingleSideLineByBound(XYZ passInPos, XYZ passOutPos, ref List<Node2D> CurNodeAry)
		{
			for (int i = 0; i < CurNodeAry.Count; i++)
			{
				Node2D node2D = CurNodeAry[i];
				for (int j = 0; j < node2D.PoleList.Count; j++)
				{
					Pole2D pole2D = node2D.PoleList[j];
					XYZ startPoint = pole2D.StartPoint;
					XYZ endPoint = pole2D.EndPoint;
					if ((Geometry.IsEqual(passInPos, startPoint, 0.0001) && Geometry.IsEqual(passOutPos, endPoint, 0.0001)) || (Geometry.IsEqual(passInPos, endPoint, 0.0001) && Geometry.IsEqual(passOutPos, startPoint, 0.0001)))
					{
						CurNodeAry[i].PoleList.RemoveAt(j);
					}
				}
			}
		}

		private bool DeleteNodeByBound(int nodeIndex, ref List<Node2D> CurNodeAry)
		{
			double eps = 0.001;
			List<KeyValuePair<XYZ, XYZ>> list = new List<KeyValuePair<XYZ, XYZ>>();
			for (int i = 0; i < CurNodeAry[nodeIndex].PoleList.Count; i++)
			{
				Pole2D pole2D = CurNodeAry[nodeIndex].PoleList[i];
				double val = this.m_ExtendLengthInfo.ExtendLength(pole2D.PositiveHalfWidth + pole2D.NegativeHalfWidth);
				if (!Geometry.Greaterthan_Or_Equal(pole2D.Length(), val, eps) || pole2D.IsExtend)
				{
					KeyValuePair<XYZ, XYZ> item = new KeyValuePair<XYZ, XYZ>(pole2D.StartPoint, pole2D.EndPoint);
					list.Add(item);
				}
			}
			if (list.Count == 0)
			{
				return false;
			}
			for (int i = 0; i < list.Count; i++)
			{
				XYZ key = list[i].Key;
				XYZ value = list[i].Value;
				this.DeleteSingleSideLineByBound(key, value, ref CurNodeAry);
			}
			CurNodeAry.RemoveAt(nodeIndex);
			return true;
		}

		private void RecursiveDeleteSingleNode(ref List<Node2D> nodeInfos)
		{
			int num = 0;
			for (int i = 0; i < nodeInfos.Count; i++)
			{
				if (nodeInfos[i].PoleList.Count < 2 && this.DeleteNodeByBound(i, ref nodeInfos))
				{
					i--;
					num++;
				}
			}
			if (num > 0)
			{
				this.RecursiveDeleteSingleNode(ref nodeInfos);
			}
		}

		private void GetAllPoleList(List<Node2D> theNodes, ref List<Pole2D> analyzedPoleList)
		{
			foreach (Node2D node2D in theNodes)
			{
				List<Pole2D> poleList = node2D.PoleList;
				using (List<Pole2D>.Enumerator enumerator2 = poleList.GetEnumerator())
				{
					while (enumerator2.MoveNext())
					{
						Pole2D pole = enumerator2.Current;
						int num = analyzedPoleList.FindIndex((Pole2D item) => item.SameAs(pole));
						if (num == -1)
						{
							analyzedPoleList.Add(pole);
						}
					}
				}
			}
		}

		private PoleAnalyzer.ExtendLengthInfo m_ExtendLengthInfo;

		private class ExtendLengthInfo
		{
			public ExtendLengthInfo(bool isExtendLength, double extendLength, double wallWidthMultiple, bool useMaximumLengthLimit)
			{
				this.m_IsExtendLength = isExtendLength;
				this.m_ExtendLength = extendLength;
				this.m_WallWidthMultiple = wallWidthMultiple;
				if (useMaximumLengthLimit)
				{
					this.m_MaxExtendLength = Common.MMToFeet(500.0);
					return;
				}
				this.m_MaxExtendLength = Common.MMToFeet(1000000.0);
			}

			public double ExtendLength(double wallWidth)
			{
				double num;
				if (this.m_IsExtendLength)
				{
					num = this.m_ExtendLength;
				}
				else
				{
					num = wallWidth * this.m_WallWidthMultiple;
				}
				if (Geometry.GreaterThan(num, this.m_MaxExtendLength))
				{
					num = this.m_MaxExtendLength;
				}
				return num;
			}

			private bool m_IsExtendLength;

			private double m_ExtendLength;

			private double m_WallWidthMultiple;

			private double m_MaxExtendLength = Common.MMToFeet(500.0);
		}
	}
}
